`include "common_header.verilog"

//  *************************************************************************
//  File : p8264_bip_check.vhd
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2008 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Denis Poverennyy
//  info@morethanip.com
//  *************************************************************************
//  Description : BIP Checker with EEE82 support (down counter derive)
//  Version     : $Id: p8264_bip_check.v,v 1.1 2014/08/04 22:11:33 wt Exp $
//  *************************************************************************

module p8264_bip_check (

        reset,
        clk,
        data_val,
        marker_dval,
        data_in,
        sh_in,
        align_done,
`ifdef MTIPPCS82_EEE_ENA
        rx_down_count,
        vl_match_num,
`endif
        bip8_err);



input           reset;          // async active high reset
input           clk;            // system clock
input           data_val;       // Data and Sync header valid
input           marker_dval;    // Pulse at the expected Alignment Marker position
input   [63:0]  data_in;        // Data input
input   [1:0]   sh_in;          // Sync header
input           align_done;     // At least two Align Markers detected

`ifdef MTIPPCS82_EEE_ENA 

output  [7:0]   rx_down_count;  //The value that results from the bit-wise exclusive-OR of the Count Down (CD3) byte and the M0
                                //byte of the current Rapid Alignment Marker payload (see 82.2.8a).
input   [3:0]   vl_match_num;   // virtual lane id (one hot coding) 
`endif
output          bip8_err;       //  bip error (one clock pulse) 


//-------------------------------------
// Output Signals
//-------------------------------------
reg             bip8_err;

`ifdef MTIPPCS82_EEE_ENA 
reg     [7:0]   rx_down_count;
`endif

//-------------------------------------
// Internal Signals
//------------------------------------- 


`ifdef MTIPPCS82_EEE_ENA 
reg     [7:0]   bip8_0_r_latched;       // derived bit field
wire    [7:0]   m0_lane0 = 8'h90;
wire    [7:0]   m0_lane1 = 8'hF0;
wire    [7:0]   m0_lane2 = 8'hC5;
wire    [7:0]   m0_lane3 = 8'hA2;
wire    [7:0]   rx_down_count_nxt;      // the same as rx_down_count, but combinatorial

`endif

//  BIP calculation
wire    [7:0] bip8_0;           // output of the BIP function
reg     [7:0] bip8_0_r;         // registered bip8_0  
wire    [7:0] bip8_0_in;        // input to the BIP function (either previous value or all zeros - for mrker) 
          





//  BIP-8 Check
// 
assign bip8_0_in = marker_dval == 1'b 0 ? bip8_0_r : {8{1'b 0}}; 


assign bip8_0 = BIP8_CALC({data_in, sh_in}, bip8_0_in); 


// comparison between expected and derived bip
always @(posedge clk or posedge reset)
begin
        if (reset == 1'b 1)
        begin
                bip8_0_r <= {8{1'b 0}};	
                bip8_err <= 1'b 0;	
        end
        else
        begin
                if (data_val == 1'b 1)
                begin
                        bip8_0_r <= bip8_0;	
                end
                if (marker_dval == 1'b 1 & bip8_0_r != data_in[31:24] &  align_done == 1'b 1)
                begin
                        bip8_err <= 1'b 1;	
                end
                else
                begin
                        bip8_err <= 1'b 0;	
                end
        end
end


// Down count derive 

`ifdef MTIPPCS82_EEE_ENA 

assign  rx_down_count_nxt = bip8_0_r_latched ^ (vl_match_num[0]? m0_lane0:
                                                vl_match_num[1]? m0_lane1:
                                                vl_match_num[2]? m0_lane2:
                                                                 m0_lane3);                                                
always @(posedge clk or posedge reset)
begin
        if (reset == 1'b 1)
        begin
                rx_down_count <= 8'b0;
                bip8_0_r_latched <= 8'b0;	
        end
        else
        begin
                if (marker_dval == 1'b 1)
                begin
                        bip8_0_r_latched <= data_in[31:24];	
                end
                rx_down_count <= rx_down_count_nxt; 	               
        end        
end      

`endif



function [7:0] BIP8_CALC;
input   [65:0] din; 
input   [7:0] bin; 

begin
   BIP8_CALC[0] =          din[2] ^ din[10] ^ din[18] ^ din[26] ^ din[34] ^ din[42] ^ din[50] ^ din[58] ^ bin[0];
   BIP8_CALC[1] =          din[3] ^ din[11] ^ din[19] ^ din[27] ^ din[35] ^ din[43] ^ din[51] ^ din[59] ^ bin[1];
   BIP8_CALC[2] =          din[4] ^ din[12] ^ din[20] ^ din[28] ^ din[36] ^ din[44] ^ din[52] ^ din[60] ^ bin[2];
   BIP8_CALC[3] = din[0] ^ din[5] ^ din[13] ^ din[21] ^ din[29] ^ din[37] ^ din[45] ^ din[53] ^ din[61] ^ bin[3];
   BIP8_CALC[4] = din[1] ^ din[6] ^ din[14] ^ din[22] ^ din[30] ^ din[38] ^ din[46] ^ din[54] ^ din[62] ^ bin[4];
   BIP8_CALC[5] =          din[7] ^ din[15] ^ din[23] ^ din[31] ^ din[39] ^ din[47] ^ din[55] ^ din[63] ^ bin[5];
   BIP8_CALC[6] =          din[8] ^ din[16] ^ din[24] ^ din[32] ^ din[40] ^ din[48] ^ din[56] ^ din[64] ^ bin[6];
   BIP8_CALC[7] =          din[9] ^ din[17] ^ din[25] ^ din[33] ^ din[41] ^ din[49] ^ din[57] ^ din[65] ^ bin[7];
end
endfunction



endmodule // module p8264_bip_check